package com.swak.vertx.transport.vertx.endpoint;

import java.util.List;
import java.util.Set;

import com.swak.annotation.Context;
import com.swak.reactivex.context.EndPoints.EndPoint;
import com.swak.spi.SPI;
import com.swak.utils.Ints;
import com.swak.utils.Lists;
import com.swak.utils.Sets;
import com.swak.utils.StringUtils;
import com.swak.vertx.config.AbstractConfig;
import com.swak.vertx.config.ServiceBean;
import com.swak.vertx.config.VertxConfig;
import com.swak.vertx.config.VertxConfigs;
import com.swak.vertx.transport.vertx.ServiceVerticle;

import io.vertx.core.CompositeFuture;
import io.vertx.core.DeploymentOptions;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;

/**
 * 服务端点
 * 
 * @author DELL
 */
@SPI(value = "ServiceEndPoint")
public class ServiceEndPoint implements FluxEndPoint {

	private VertxConfig config;
	private Vertx vertx;

	@SuppressWarnings("unchecked")
	public List<Future<EndPoint>> start(Vertx vertx, VertxConfig config) {
		this.vertx = vertx;
		this.config = config;
		List<Future<EndPoint>> futures = Lists.newArrayList();
		Set<ServiceBean> services = this.getServices();
		for (ServiceBean service : services) {
			futures.add(this.startService(service));
		}
		return futures;
	}

	private Set<ServiceBean> getServices() {
		Set<ServiceBean> services = Sets.newOrderSet();
		Set<AbstractConfig> configs = VertxConfigs.me().getConfigs();
		for (AbstractConfig config : configs) {
			if (config instanceof ServiceBean) {
				services.add((ServiceBean) config);
			}
		}
		return services;
	}

	@SuppressWarnings({ "rawtypes" })
	private Future startService(ServiceBean service) {

		// 发布
		service.export();

		// 发布服务标示
		List<Future> futures = Lists.newArrayList();

		// 以worker 的方式发布 默认是并发的执行代码， 默认只发布EVENT_LOOP的一半，也就是实际的核心数， 可以自定义发布的个数
		DeploymentOptions options = new DeploymentOptions().setWorker(true);

		// 运行的线程模型： min(定义的IO线程数， def(需要的并行度, 核心数))
		if (service.getContext() == Context.IO) {
			options.setWorker(false)
					.setInstances(Ints.min(config.getEventLoopPoolSize(),
							service.getInstances() <= 0 ? VertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE / 2
									: service.getInstances()));
		}
		// 运行的线程模型： def(需要的并行度, 1)
		else if (service.getContext() == Context.Order) {
			options.setWorker(true).setInstances(service.getInstances() <= 0 ? 1 : service.getInstances());
		}
		// 运行的线程模型： def(需要的并行度, 工作线程数)
		else if (service.getContext() == Context.Concurrent) {
			options.setWorker(true).setInstances(
					service.getInstances() <= 0 ? config.getWorkerPoolSize() / 2 : service.getInstances());
		}

		// worker线程，自定义的线程池，则重新定义任务的数量
		if (options.isWorker() && StringUtils.isNotBlank(service.getPool())) {
			String usePool = service.getPool();
			int poolSize = service.getWorkers();
			options.setWorkerPoolName("vert.x-worker-" + usePool + "-thread").setWorkerPoolSize(poolSize)
					.setInstances(service.getInstances() <= 0 ? poolSize / 2 : service.getInstances());
		}

		// 发布一个Deployment 对应多个 Verticle
		Future<String> stFuture = Future
				.future(s -> vertx.deployVerticle(() -> new ServiceVerticle(service), options, s));
		futures.add(stFuture.map(id -> service.setDeploymentID(id)));

		// 合并成一个结果
		return CompositeFuture.all(futures).map(res -> null);
	}
}